package com.aicoq.example.stock.service.impl;

import com.aicoq.example.stock.domain.StockDayInfoDto;
import com.aicoq.example.stock.persist.mapper.StockDayInfoMapper;
import com.aicoq.example.stock.persist.mapper.StockInfoMapper;
import com.aicoq.example.stock.persist.model.StockDayInfo;
import com.aicoq.example.stock.persist.model.StockDayInfoKey;
import com.aicoq.example.stock.persist.model.StockInfo;
import com.aicoq.example.stock.service.SyncStockService;
import com.aicoq.example.utils.http.OkHttpUtils;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Service
public class SyncStockServiceImpl implements SyncStockService {

    @Autowired
    private StockDayInfoMapper stockDayInfoMapper;
    @Autowired
    private StockInfoMapper stockInfoMapper;

    private final static Logger logger = LoggerFactory.getLogger(SyncStockServiceImpl.class);
    private final static int PAGE_SIZE = 40;

    @Override
    public void syncStock(List<String> markets) {
        doSyncStock(markets);
    }

    private void doSyncStock(List<String> markets) {
        var occurDate = occurDate();
        var marketList = getMarkets(markets);
        var executorService = Executors.newSingleThreadExecutor();
        executorService.execute(() -> {
            for (var market : marketList) {
                saveSyncStockMarket(market, occurDate);
            }
            logger.info("跑完了");
        });
    }

    private void saveSyncStockMarket(String market, int occurDate) {
        int page = 1;
        while (true) {
            var stockInfoList = queryStockFromSina(market, page++);
            if (stockInfoList == null) {
                break;
            }
            for (var stock : stockInfoList) {
                var stockDayInfo = new StockDayInfo();
                BeanUtils.copyProperties(stock, stockDayInfo);

                stockDayInfo.setOccurDate(occurDate);

                var stockDayInfoKey = new StockDayInfoKey();
                stockDayInfoKey.setSymbol(stock.getSymbol());
                stockDayInfoKey.setOccurDate(occurDate);
                if (stockDayInfoMapper.selectByPrimaryKey(stockDayInfoKey) != null) {
                    stockDayInfoMapper.updateByPrimaryKeySelective(stockDayInfo);
                } else {
                    stockDayInfoMapper.insertSelective(stockDayInfo);
                }

                if (stockInfoMapper.selectByPrimaryKey(stock.getSymbol()) == null) {
                    var stockInfo = new StockInfo();
                    stockInfo.setSymbol(stock.getSymbol());
                    stockInfo.setCode(stock.getCode());
                    stockInfo.setName(stock.getName());
                    stockInfoMapper.insertSelective(stockInfo);
                }
            }
            if (stockInfoList.size() < PAGE_SIZE) {
                break;
            }
            sleep();
        }
    }

    private List<StockDayInfoDto> queryStockFromSina(String market, int page) {
        var url = "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQNodeData?page=%d&num=%s&sort=symbol&asc=1&node=%s&symbol=&_s_r_a=init";
        var formatUrl = String.format(url, page, PAGE_SIZE, market);
        var result = OkHttpUtils.get(formatUrl);
        return JSON.parseArray(result, StockDayInfoDto.class);
    }

    private void sleep() {
        try {
            TimeUnit.SECONDS.sleep(new Random().nextLong(10L));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    private int occurDate() {
        var calendar = Calendar.getInstance();

        var dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
        var month = calendar.get(Calendar.MONTH) + 1;

        var date = String.valueOf(calendar.get(Calendar.YEAR)) +
                (month < 10 ? "0" + month : month) +
                (dayOfMonth < 10 ? "0" + dayOfMonth : dayOfMonth);

        return Integer.parseInt(date);
    }

    private List<String> getMarkets(List<String> markets) {
        if (markets != null && !markets.isEmpty()) {
            return markets;
        }
        return Lists.newArrayList("sh_a", "sz_a", "hs_bjs");
    }
}
